﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using SHack.Helper;
using System.Threading;
using System.Diagnostics;
using SMDS;


namespace SHack
{
    class PortScan:BaseScan
    {
        public delegate void ScanFoundPortHandler(string ip, int port,string mark="");
        public event ScanFoundPortHandler ScanFoundPortEvent;

        public delegate void ScaningTestPassHandler(string ip, int port, string mark);
        public event ScaningTestPassHandler ScaningTestPassEvent;

        private Queue<string> _quIPS = new Queue<string>();
        private List<string> _ltPorts = new List<string>();
        private SortedList<string, VarFile> _slGetPass;
        private object _lockerIPS = new object();

        private string _singleIP = null;
        private int _singlePort = 0;
        private string _singleMethod = null;
        private bool _singleFound = false;

        public bool Start(SortedList<string, VarFile> slGetPass, int threadCount, int timeOut, string startIP, string endIP, string[] ports,string signleMethod=null)
        {
            Regex reg = new Regex(@"\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}");
            if (!reg.Match(startIP).Success)
            {
                _error = "起始IP地址不符合规则！";
                return false;
            }
            if (!reg.Match(endIP).Success)
            {
                _error = "起始结束地址不符合规则！";
                return false;
            }

            _slGetPass = slGetPass;

            _quIPS.Clear();
            _ltPorts.Clear();
            _lastTime = DateTime.Now;
            _passCount = 0;
            _totalCount = 0;
            _timeOut = timeOut;
            _succCount = 0;

            PortTestHelper.TimeOut = timeOut;
            _isrun = true;

            _singleMethod = signleMethod;
            _singleFound = false;

            if (signleMethod == null)
            {


                long sIP = IPHelper.IPToNumber(startIP);
                long eIP = IPHelper.IPToNumber(endIP);

                if (sIP > eIP)
                {
                    long tmp = eIP;
                    eIP = sIP;
                    sIP = eIP;
                }

                foreach (string port in ports)
                {
                    if (port.Contains("-"))
                    {
                        string[] sp = port.Split('-');
                        int minPort = Convert.ToInt32(sp[0]);
                        int maxPort = Convert.ToInt32(sp[1]);

                        if (minPort < 1 || minPort > 65535 || maxPort < 1 || maxPort > 65535)
                        {
                            _error = "端口号范围应为1-65535！";
                            return false;
                        }

                        if (minPort > maxPort)
                        {
                            int tmp = maxPort;
                            maxPort = minPort;
                            minPort = tmp;
                        }
                        for (int i = minPort; i <= maxPort; i++)
                            _ltPorts.Add(i.ToString());

                    }
                    else
                    {
                        int p = Convert.ToInt32(port);
                        if (p < 1 || p > 65535)
                        {
                            _error = "端口号范围应为1-65535！";
                            return false;
                        }
                        _ltPorts.Add(port);
                    }
                }

                for (long i = sIP; sIP <= eIP; sIP++)
                {
                    string ip = IPHelper.NumberToIP(sIP);
                    foreach (string port in _ltPorts)
                    {
                        _quIPS.Enqueue(ip + "," + port.ToString());
                    }
                }

                _totalCount = _quIPS.Count;
                for (int i = 0; i < threadCount; i++)
                {
                    new Thread(thScanPort).Start();
                }
            }
            else
            {
                _singleIP = startIP;
                _singlePort = Convert.ToInt32(ports[0]); 
                _totalCount = _slGetPass.ContainsKey(signleMethod) ? _slGetPass[signleMethod].TotalCount : 0;
                for (int i = 0; i < threadCount; i++)
                {
                    new Thread(thScanPortSingle).Start();
                }

            }

           

            return true;        
        }

        public bool Stop()
        {
            _isrun = false;
            return true;
        }

        private void thScanPort()
        {
            long ticks = 0;
            while (_isrun && _quIPS.Count > 0)
            {
                try
                {
                    string r;
                    lock (_lockerIPS)
                    {
                        if (_quIPS.Count == 0)
                            break;

                        r = _quIPS.Dequeue();

                    }
                    AddPass();

                    string[] sp = r.Split(',');
                    string ip = sp[0];
                    int port = Convert.ToInt32(sp[1]);

                    if (PortTestHelper.Test(ip, port, ref ticks))
                    {



                        if (_slGetPass != null)
                        {
                            if (GetPassAuto(ip, port))
                            {
                                AddSucc();
                            }
                            if (_quIPS.Count == 0)
                            {
                                CallStop();
                                return;
                            }
                        }
                        else
                        {
                            AddSucc();
                            if (ScanFoundPortEvent != null)
                                ScanFoundPortEvent(ip, port, ticks.ToString() + "ms");
                        }
                    }



                }
                catch (Exception ex)
                {
                    Console.WriteLine("PortScan.cs->thScanStop()", ex.Message);
                }
            }

            if (_slGetPass != null)
            {

            }
            else
            {
                CallStop();
            }
        }

        private bool GetPassAuto(string ip,int port)
        {
            bool ret =false;
            if (port == 21 && _slGetPass.ContainsKey("ftp"))
            {
                ret = TestPass("ftp", ip, port);
            }
            else if (port == 22 && _slGetPass.ContainsKey("ssh"))
            {
                ret = TestPass("ssh", ip, port);
            }
            else if (port == 445 && _slGetPass.ContainsKey("smb"))
            {
                ret = TestPass("smb", ip, port);
            }
            else if (port == 1433 && _slGetPass.ContainsKey("sqlserver"))
            {
                ret = TestPass("sqlserver", ip, port);
            }
            else if (port == 3306 && _slGetPass.ContainsKey("mysql"))
            {
                ret = TestPass("mysql", ip, port);
            }
            else if (port == 3389 && _slGetPass.ContainsKey("remote"))
            {
                ret = TestPass("remote",ip, port);
            }
            else
            { 
                
            }
            return ret;
        }

        private void thScanPortSingle()
        {

            SortedList<string, string> sl;
            string method = _singleMethod;
            string ip = _singleIP;
            int port = _singlePort;
            
            try
            {
                while (_isrun &&!_singleFound)
                {
                    lock (_lockerIPS)
                    {
                        sl = _slGetPass[_singleMethod].Get();
                    }
                    if (sl == null)
                    {
                        break;
                    }
                    AddPass();
                    if (ScaningTestPassEvent != null)
                        ScaningTestPassEvent(ip, port, "尝试登陆" + sl["user"] + "->" + sl["pass"] + "...");

                    try
                    {

                        bool ret = false;
                        if (method == "ssh")
                        {
                            ret = GetPassHelper.CheckSSH(ip, port, sl["user"], sl["pass"]);
                        }
                        else if (method == "ftp")
                        {
                            ret = GetPassHelper.CheckFTP(ip, port, sl["user"], sl["pass"]);
                        }
                        else if (method == "mysql")
                        {
                            ret = GetPassHelper.CheckMysql(ip, port, sl["user"], sl["pass"]);
                        }
                        else if (method == "sqlserver")
                        {
                            ret = GetPassHelper.CheckSqlServer(ip, port, sl["user"], sl["pass"]);
                        }
                        else if (method == "smb")
                        {
                            ret = GetPassHelper.CheckSMB(ip, port, sl["user"], sl["pass"]);
                        }
                        else if (method == "remote")
                        {
                            ret = GetPassHelper.CheckRemote(ip, port, sl["user"], sl["pass"]);
                        }

                        if (ret)
                        {
                            _singleFound = true;
                            AddSucc();
                            if (ScanFoundPortEvent != null)
                                ScanFoundPortEvent(ip, port, "登陆成功：" + sl["user"] + "," + sl["pass"]);

                            break;
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("PortScan.cs->TestPass()", ex.Message);
                    }


                }
            }
            catch (Exception ex2)
            {
                Console.WriteLine("PortScan.cs->TestPass()", ex2.Message);

            }
            if (!_singleFound)
            {
                if (ScanFoundPortEvent != null)
                    ScanFoundPortEvent(ip, port, "未发现");
            }
            CallStop();
        }


        public bool TestPass(string method,string ip, int port)
        {
            if (!_slGetPass.ContainsKey(method))
                return false;


            VarFile vf = _slGetPass[method].Clone();
            SortedList<string, string> sl;
            try
            {
                while (_isrun)
                {
                    sl = vf.Get();
                    if (sl == null)
                    {
                        break;
                    }
                    if (ScaningTestPassEvent != null)
                        ScaningTestPassEvent(ip, port, "尝试登陆" + sl["user"] + "->" + sl["pass"] + "...");

                    try
                    {

                        bool ret = false;
                        if (method == "ssh")
                        {
                            ret = GetPassHelper.CheckSSH(ip, port, sl["user"], sl["pass"]);
                        }
                        else if (method == "ftp")
                        {
                            ret = GetPassHelper.CheckFTP(ip, port, sl["user"], sl["pass"]);
                        }
                        else if (method == "mysql")
                        {
                            ret = GetPassHelper.CheckMysql(ip, port, sl["user"], sl["pass"]);
                        }
                        else if (method == "sqlserver")
                        {
                            ret = GetPassHelper.CheckSqlServer(ip, port, sl["user"], sl["pass"]);
                        }
                        else if (method == "smb")
                        {
                            ret = GetPassHelper.CheckSMB(ip, port, sl["user"], sl["pass"]);
                        }
                        else if (method == "remote")
                        {
                            ret = GetPassHelper.CheckRemote(ip, port, sl["user"], sl["pass"]);
                        }

                        if (ret)
                        {
                            if (ScanFoundPortEvent != null)
                                ScanFoundPortEvent(ip, port, "登陆成功：" + sl["user"] + "," + sl["pass"]);

                            return true;
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("PortScan.cs->TestPass()", ex.Message);
                    }


                }
            }
            catch (Exception ex2)
            {
                Console.WriteLine("PortScan.cs->TestPass()", ex2.Message);
            
            }

            return false;
        }

    }
}
